package com.authine.cloudpivot.ext.service.impl;

import com.alibaba.cola.dto.RequestContext;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.cola.exception.BizException;
import com.authine.cloudpivot.data.support.PageImpl;
import com.authine.cloudpivot.ext.constants.AppConst;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.constants.PlatformConst;
import com.authine.cloudpivot.ext.domain.query.MallQuery;
import com.authine.cloudpivot.ext.domain.vo.GoodsAttrData;
import com.authine.cloudpivot.ext.domain.vo.MallGoodsVO;
import com.authine.cloudpivot.ext.dto.GatewayResponse;
import com.authine.cloudpivot.ext.dto.goods.VendorGoodsEntity;
import com.authine.cloudpivot.ext.dto.system.OrganizationDto;
import com.authine.cloudpivot.ext.dto.system.UserDto;
import com.authine.cloudpivot.ext.entity.goods.GoodsEntity;
import com.authine.cloudpivot.ext.entity.goods.GoodsFullEntity;
import com.authine.cloudpivot.ext.enums.ReviewStatusEnum;
import com.authine.cloudpivot.ext.enums.goods.GoodsType;
import com.authine.cloudpivot.ext.enums.goods.MallSortEnum;
import com.authine.cloudpivot.ext.model.goods.GoodsFullModel;
import com.authine.cloudpivot.ext.model.goods.MallGoodsModel;
import com.authine.cloudpivot.ext.service.GoodsService;
import com.authine.cloudpivot.ext.utils.BigDecimalUtils;
import com.authine.cloudpivot.ext.utils.BoServiceUtils;
import com.authine.cloudpivot.ext.utils.FinancialCalculationUtils;
import com.authine.cloudpivot.ext.utils.JdbcTemplateUtils;
import com.authine.cloudpivot.ext.utils.boQuery.BoQueryUtils;
import com.authine.cloudpivot.ext.utils.system.OrgUtils;
import com.authine.cloudpivot.ext.utils.system.RoleUtils;
import com.authine.cloudpivot.ext.utils.system.SessionUser;
import com.authine.cloudpivot.ext.utils.system.UserUtils;
import com.authine.cloudpivot.metadata.design.dto.clientobject.domainmodel.schema.BizSchema;
import com.authine.cloudpivot.metadata.design.dto.clientobject.domainmodel.schema.Properties;
import com.authine.cloudpivot.metadata.design.dto.clientobject.domainmodel.schema.ValueType;
import com.authine.mvp.app.launcher.domain.gateway.appmeata.query.MetaQueryI;
import com.authine.mvp.app.launcher.domain.utills.ApplicationContextUtils;
import com.authine.mvp.app.launcher.dto.bo.response.BO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Sets;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
public class GoodsServiceImpl implements GoodsService {
    MetaQueryI metaQueryI = ApplicationContextUtils.getBean(MetaQueryI.class);

    private GoodsServiceImpl() {
    }

    public static GoodsServiceImpl getInstance() {
        return GoodsServiceImplBuilder.instance;
    }

    /**
     * 添加历史记录
     *
     * @param oldList
     */
    @Override
    public void addGoodsHistory(final List<Map<String, Object>> oldList) {
        List<Map<String, Object>> historyList = new ArrayList<>();
        BizSchema bizSchemaByModel = metaQueryI.getBizSchemaByModel(ModelConst.T_GOODSES_HISTORY);
        Stream<Properties> propertiesStream = bizSchemaByModel.getProperties().stream().filter(a -> !a.getIsSystemProperty());

        oldList.forEach(oldData -> {
            Map<String, Object> historyMap = new HashMap<>();
            propertiesStream.forEach(p -> {
                String code = p.getCode();
                Object val = oldData.get(code);
                if (val == null) {
                    historyMap.put(code, null);
                } else {
                    ValueType valueType = p.getValueType();
                    if (ValueType.RADIO_PERSON == valueType || ValueType.RADIO_DEPARTMENT == valueType) {
                        historyMap.put(code, val);
                    } else if (ValueType.BOOLEAN == valueType) {
                        historyMap.put(code, "1".equals(String.valueOf(val)));
                    } else {
                        historyMap.put(code, val);
                    }
                }
            });
            historyMap.put("goodses_id", oldData.get("id"));
            historyList.add(historyMap);
        });


        SingleResponse<BO> bo = BoServiceUtils.createBo(ModelConst.T_GOODSES_HISTORY, historyList);

        if (bo.isSuccess() && log.isDebugEnabled()) {
            log.debug("添加修改记录成功");
        }
    }

    public List<VendorGoodsEntity> queryEqualGoods(String vendorId, String name, String brand, String model,
                                                   String spec, String unit, String packageUnit, BigDecimal packageNum) {


        JdbcTemplateUtils query = JdbcTemplateUtils.builder(ModelConst.T_GOODSES)
                .selectField(" * ")
                .eq("brand", brand)
                .eq("model", model)
                .eq("spec", spec)
                .eq("unit", unit)
                .eq("package_unit", packageUnit)
                .eq("vendor_id -> '$.id'", vendorId)
                .eq("name", name)
                .in("type", Arrays.asList(GoodsType.Mall.ordinal(), GoodsType.Virtual.ordinal()));

        if (packageNum != null) {
            query.eq("package_num", packageNum);
        }

        List<VendorGoodsEntity> vendorGoodsEntities = query.queryForJavaBean(VendorGoodsEntity.class);


        return vendorGoodsEntities;
    }

    @Override
    public boolean insertAndUpdateList(List<Map<String, Object>> insert, List<Map<String, Object>> update) {
        boolean flag = true;
        if (CollectionUtils.isNotEmpty(insert)) {

            flag = BoServiceUtils.createBo(ModelConst.T_GOODSES, insert).isSuccess();
        }

        if (CollectionUtils.isNotEmpty(update) && flag) {
            flag = BoServiceUtils.updateMainBo(ModelConst.T_GOODSES, update).isSuccess();
        }

        return flag;
    }

    private Collection<String> splitter = Sets.newHashSet(",", "，");

    @Override
    public BigDecimal calculateSkuPrice(GoodsFullEntity entity, OrganizationDto customerAccount, OrganizationDto vendor) {
        if (entity == null) {
            return null;
        }
        BigDecimal SHOP_PLATFORM_RATE = new BigDecimal("0.03");
        BigDecimal pretaxPrice, taxRate;
        String vendorId = entity.getVendor_id().get(0).getId();
        if (null != entity.getAdjust_pretax_price()) {
            pretaxPrice = entity.getAdjust_pretax_price();
        } else {
            pretaxPrice = entity.getPretax_price();
        }
        taxRate = entity.getTax_rate();
        if (vendorId == null || pretaxPrice == null || taxRate == null || SHOP_PLATFORM_RATE == null) {
            log.error(String.format("vendorId => %s, pretaxPrice => %s, taxRate => %s, shopPlatformRate => %s", vendorId, pretaxPrice, taxRate, SHOP_PLATFORM_RATE));
            throw new BizException("商品价格获取错误!");
        }

        BigDecimal freightRatioByOrgId;
        if (ObjectUtils.notEqual(vendor, null)) {
            freightRatioByOrgId = vendor.getFreight_ratio();
        } else {
            freightRatioByOrgId = OrgUtils.getOrgByOrgId(vendorId).getFreight_ratio();
        }
        Integer statementCycle = null;
        if (ObjectUtils.notEqual(customerAccount, null)) {
            statementCycle = customerAccount.getStatement_cycle();
        } else {
            statementCycle = OrgUtils.getOrgByUserId().getStatement_cycle();

            if (null == statementCycle || statementCycle < 0) {
                statementCycle = 0;
            }
        }
        freightRatioByOrgId = Optional.ofNullable(freightRatioByOrgId).orElse(BigDecimal.ZERO);
        try {
            BigDecimal ceil = new BigDecimal(statementCycle).divide(new BigDecimal("30.0"));
            BigDecimal accountPeriodRate = BigDecimalUtils.mul(ceil, new BigDecimal("1.5")).movePointLeft(2);
            BigDecimal finalRate = BigDecimalUtils.add(BigDecimalUtils.add(BigDecimalUtils.add(SHOP_PLATFORM_RATE, freightRatioByOrgId), accountPeriodRate), BigDecimal.ONE);
            BigDecimal afterTaxPrice = FinancialCalculationUtils.calculatePriceByPretaxPrice(pretaxPrice, taxRate);
            BigDecimal price = BigDecimalUtils.round(BigDecimalUtils.mul(afterTaxPrice, finalRate), 2);
            BigDecimal calculatePretaxPrice = BigDecimalUtils.round(BigDecimalUtils.div(price, taxRate.add(BigDecimal.ONE)), 16);
            entity.setPretax_price(calculatePretaxPrice);
            return price;
        } catch (Exception e) {
            throw new BizException("商品价格获取错误!");
        }
    }

    @Override
    public GatewayResponse<List<GoodsFullEntity>> pageMallGoodsByIds(final List<String> ids, final Boolean restrictedBrands) {

        UserDto currentUser = UserUtils.getCurrentUser();
        BoQueryUtils queryList = BoQueryUtils.Builder(ModelConst.T_GOODSES);
        BoQueryUtils.BoCondition condition = queryList.condition()
                .eq("enabled", true)
                .eq("deleted", false)
                .eq("profile_enabled", true)
                .in("id", ids)
                .eq("saled", true)
                .eq("review_status", ReviewStatusEnum.REVIEW_CONSENT.ordinal())
                .eq("mall_sales", true)
                .in("type", Arrays.asList(GoodsType.Mall.ordinal(), GoodsType.Virtual.ordinal()))
                .gte("expiry", new Date());


        OrganizationDto currentOrg = OrgUtils.getOrgByUserId();
        if (Objects.nonNull(restrictedBrands) && restrictedBrands) {
            setMajorBrands(condition, currentOrg);
        }

        PageImpl<GoodsFullEntity> page = queryList.listBO(GoodsFullEntity.class);

        if (page.getTotal() > 0) {
            page.getContent().forEach(e -> {
                e.setPrice(calculateSkuPrice(e, currentOrg, null));
                e.setOrg_fullname(PlatformConst.ORGANIZATION_NAME);
            });

        }
        List<GoodsFullEntity> content = (List<GoodsFullEntity>) page.getContent();

        return GatewayResponse.success((int) page.getTotal(), content);
    }

    private void setMajorBrands(BoQueryUtils.BoCondition condition, OrganizationDto org) {
        boolean isVendor = RoleUtils.existByUserIdAndRoleName(RequestContext.getCorpLoginId(), PlatformConst.ROLE_VENDOR_ADMIN);
        if (isVendor && StringUtils.isNotEmpty(StringUtils.trimToNull(org.getMajor_brand()))) {
            condition.in("brand", (List) majorBrandFilter(org.getMajor_brand()));
        }
    }

    public Collection<String> majorBrandFilter(String majorBrand) {
        Set<String> split = null;
        for (String s1 : splitter) {
            if (majorBrand.contains(s1) && split == null) {
                split = Arrays.stream(majorBrand.split(s1)).map(StringUtils::trimToNull).filter(StringUtils::isNotEmpty).collect(Collectors.toSet());
            } else if (majorBrand.contains(s1) && split != null) {
                split = split.stream().map(StringUtils::trimToNull).filter(StringUtils::isNotEmpty).flatMap(e -> Arrays.stream(e.split(s1)).map(String::trim)).collect(Collectors.toSet());
            }
        }
        return Optional.ofNullable(split).orElseGet(() -> Sets.newHashSet(majorBrand));
    }

    @Override
    public boolean updateGoods(Map<String, Object> map) {

        Object id = map.get("id");
        map.remove("id");
        if (id != null) {
            int updateCount = JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODSES)
                    .putFieldAndVal(map)
                    .eq("id", id)
                    .update();

            return updateCount > 0;
        }


        return false;
    }

    @Override
    public GoodsEntity getGoodsById(final String id) {

        List<GoodsEntity> list = JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODSES)
                .selectField(" * ")
                .eq("id", id)
                .queryForJavaBean(GoodsEntity.class);

        return list.isEmpty() ? null : list.get(0);
    }

    @Override
    public GatewayResponse<MallGoodsVO> pageMallGoods(MallQuery query) {
        //添加前置条件
        query = Optional.ofNullable(query).orElseGet(MallQuery::of).setAttrPage(Optional.ofNullable(query.getAttrPage()).orElse(1))
                .setAttrLimit(Optional.ofNullable(query.getAttrLimit()).orElse(20)).setEnabled(true).setProfileEnabled(true)
                .setSaled(true).setReviewStatus(ReviewStatusEnum.REVIEW_CONSENT.ordinal()).setMallSales(true)
                .setType(Sets.newHashSet(GoodsType.Mall.ordinal(), GoodsType.Virtual.ordinal())).setGteExpiry(new Date()).setAttrQuery(true);
        //排序
        query.setSort(MallSortEnum.idOf(query.getSortType()).sql);

        JdbcTemplateUtils jdbcQuery = JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODSES).selectField(" * ");
        //构建sql查询条件
        query.condition(jdbcQuery);
        query.conditionPage(jdbcQuery);
        query.conditionSort(jdbcQuery);

        OrganizationDto org = OrgUtils.getOrgByUserId();
        SessionUser sessionUser = new SessionUser();

        //添加品牌过滤
        if (sessionUser.isVendor() && StringUtils.isNotEmpty(StringUtils.trimToNull(org.getMajor_brand()))) {
            jdbcQuery.in("brand", majorBrandFilter(org.getMajor_brand()));
        }
        //获取商品数据
        List<GoodsFullEntity> goodsFullEntities = jdbcQuery.queryForJavaBean(GoodsFullEntity.class);
        List<GoodsFullModel> goods;
        if (goodsFullEntities.isEmpty()) {
            return GatewayResponse.failed("获取数据失败");
        }

        if (Objects.isNull(query.getAttrQuery()) || !query.getAttrQuery()) {
            goods = goodsFullEntities.stream().map(GoodsFullModel::entityToModel).collect(Collectors.toList());
            return GatewayResponse.success(goods.size(), MallGoodsVO.of().setSku(goods));

        }


        goodsFullEntities.forEach(e -> {
            e.setPrice(calculateSkuPrice(e, org, null));
            e.setOrg_fullname(PlatformConst.ORGANIZATION_NAME);
        });
        goods = goodsFullEntities.stream().map(GoodsFullModel::entityToModel).collect(Collectors.toList());
        goods.forEach(e -> e.setCalculatePrice(true));


        //开始获取属性
        String fields = " GROUP_CONCAT(name) as name,GROUP_CONCAT(brand) as brand,GROUP_CONCAT(model) as model,GROUP_CONCAT(spec) as spec  ";
        List<MallGoodsModel> mallGoodsModels = JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODSES)
                .selectField(fields)
                .eq("enabled", query.getEnabled())
                .eq("saled", query.getSaled())
                .eq("review_status", query.getReviewStatus())
                .eq("mall_sales", query.getMallSales())
                .in("type", query.getType())
                .eq("mall_featured", query.getMallFeatured())
                .gte("expiry", query.getGteExpiry())
                .eq("catalog", query.getCatalog())
                .queryForJavaBean(MallGoodsModel.class);

        MallGoodsModel mallGoodsModel;
        if (!mallGoodsModels.isEmpty()) {
            mallGoodsModel = mallGoodsModels.get(0);
        }
        mallGoodsModel = MallGoodsModel.of();
        MallGoodsVO.MallGoodsVOBuilder builder = MallGoodsVO.builder();
        // 对属性进行处理
        if (StringUtils.isNotEmpty(mallGoodsModel.getName())) {
            GoodsAttrData name = GoodsAttrData.of().setAttr(Arrays.stream(mallGoodsModel.getName().split(",")).filter(StringUtils::isNotEmpty).collect(Collectors.toList()))
                    .setCount(mallGoodsModel.getNameCount());
            builder.name(name);
        }
        if (StringUtils.isNotEmpty(mallGoodsModel.getBrand())) {
            GoodsAttrData brand = GoodsAttrData.of().setAttr(Arrays.stream(mallGoodsModel.getBrand().split(",")).filter(StringUtils::isNotEmpty).collect(Collectors.toList()))
                    .setCount(mallGoodsModel.getBrandCount());
            builder.brand(brand);
        }
        if (StringUtils.isNotEmpty(mallGoodsModel.getModel())) {
            GoodsAttrData model = GoodsAttrData.of().setAttr(Arrays.stream(mallGoodsModel.getModel().split(",")).filter(StringUtils::isNotEmpty).collect(Collectors.toList()))
                    .setCount(mallGoodsModel.getModelCount());
            builder.model(model);
        }
        if (StringUtils.isNotEmpty(mallGoodsModel.getSpec())) {
            GoodsAttrData spec = GoodsAttrData.of().setAttr(Arrays.stream(mallGoodsModel.getSpec().split(",")).filter(StringUtils::isNotEmpty).collect(Collectors.toList()))
                    .setCount(mallGoodsModel.getSpecCount());
            builder.spec(spec);
        }

        for (GoodsFullModel good : goods) {
            if (good.getImages() != null && good.getImages().contains("http:")) {
                String s = good.getImages().replace("http", "https");
                good.setImages(s);
            }
        }
        MallGoodsVO vo = builder.sku(goods).build();
        return GatewayResponse.success(goods.size(), vo);
    }

    @Override
    public MallGoodsModel pageMallFullGoods(MallQuery query) {

        //排序
        query.setSort(MallSortEnum.idOf(query.getSortType()).sql);

        JdbcTemplateUtils jdbcQuery = JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODSES).selectField(" * ");
        //构建sql查询条件
        query.condition(jdbcQuery);
        query.conditionPage(jdbcQuery);
        query.conditionSort(jdbcQuery);
        //获取商品数据
        List<GoodsFullEntity> goodsFullEntities = jdbcQuery.queryForPOJOList(GoodsFullEntity.class, true);
        goodsFullEntities.forEach(e -> e.setOrg_fullname(PlatformConst.ORGANIZATION_NAME));
        List<GoodsFullModel> goods = goodsFullEntities.stream().map(GoodsFullModel::entityToModel).collect(Collectors.toList());


        if (Objects.isNull(query.getAttrQuery()) || !query.getAttrQuery()) {
            goods = goodsFullEntities.stream().map(GoodsFullModel::entityToModel).collect(Collectors.toList());
            return MallGoodsModel.of().setGoods(goods);

        }
        //开始获取属性
        String fields = " GROUP_CONCAT(name) as name,GROUP_CONCAT(brand) as brand,GROUP_CONCAT(model) as model,GROUP_CONCAT(spec) as spec from from i_commoditymaterials_t_goodses ";
        List<MallGoodsModel> mallGoodsModels = JdbcTemplateUtils.builder(AppConst.COMMODITYMATERIALS, ModelConst.T_GOODSES)
                .selectField(fields)
                .eq("enabled", query.getEnabled())
                .eq("saled", query.getSaled())
                .eq("review_status", query.getReviewStatus())
                .eq("mall_sales", query.getMallSales())
                .in("type", query.getType())
                .eq("mall_featured", query.getMallFeatured())
                .gte("expiry", query.getGteExpiry())
                .eq("catalog", query.getCatalog())
                .queryForJavaBean(MallGoodsModel.class);

        MallGoodsModel mallGoodsModel = null;
        if (mallGoodsModels.isEmpty()) {
            mallGoodsModel = mallGoodsModels.get(0);
        }
        return Optional.ofNullable(mallGoodsModel).orElse(MallGoodsModel.of()).setGoods(goods);
    }

    private static class GoodsServiceImplBuilder {
        private static final GoodsServiceImpl instance = new GoodsServiceImpl();
    }
}
